﻿"use strict";

var uk = require('./def.js');
require('./netevent.js');
require('./action.js');
require('./buff.js');
require('./cards.js');
require('./roles.js');
require('./hero.js');
require('./monsterai.js');
require('./monster.js');
require('./room.js');
require('./station.js');
module.exports = uk;

uk.hall = {
    users:{},
    usercount:0,
    status:uk.hall_status.NONE,
    savequeue:0,
    savequeue_quest_finish:false,

    /**初始化 */
    initialize:function(){
        if(uk.db == null){
            console.log('db is null');
            return false;
        }else if(this.status != uk.hall_status.NONE){
            console.log('hall has initialized');
            return false;
        }
        this.status = uk.hall_status.WORKING;
        return true;
    },

    /**关闭 */
    shutdown:function(_shutcallback){
        var utmp = this.users;
        this.users = {};
        this.status = uk.hall_status.CLOSING;
        this.savequeue = 0;
        this.savequeue_quest_finish = false;
        this.shutdown_callback = _shutcallback;
        for(var i in this.rooms){
            var room = this.rooms[i];
            /**解散房间且不通知客户端 */
            room.dismiss(false);
        }
        for(var i in utmp){
            var u = utmp[i];
            this.user_logout(u);
        }
        this.usercount = 0;
        this.savequeue_quest_finish = true;
        if(this.savequeue == 0){
            this.status = uk.hall_status.END;
            if(this.shutdown_callback)
                this.shutdown_callback();
        }
    },

    /** 创建用户 */
    create_user:function(id){
        return {
            currole:null,
            info:{
                id:id,
                name:'访客'+uk.rand(10000,999999999)
            },
            roles:{},
            sock:null
        };
    },

    on_connect:function(socket){
        if(this.status != uk.hall_status.WORKING){
            console.log('server in closing,ingore connect');
            return;
        }
        socket.name = uk.getnewguid();
        socket.user = null;
		console.log('a user connected:'+socket.name);

        socket.on(uk.netevents.REGISTER,function(obj){ uk.hall.on_register(socket,obj);} );
        socket.on(uk.netevents.LOGIN,function(obj){ uk.hall.on_login(socket,obj);} );
        socket.on(uk.netevents.CREATEROLE,function(obj){ uk.hall.on_createrole(socket,obj);} );
        socket.on(uk.netevents.ENTER,function(obj){ uk.hall.on_enterroom(socket,obj);} );
        socket.on(uk.netevents.LEAVE,function(obj){ uk.hall.on_leaveroom(socket,obj);} );
        socket.on(uk.netevents.READY,function(obj){ uk.hall.on_userready(socket,obj);} );
        socket.on(uk.netevents.VISITORLOGIN,function(obj){ uk.hall.on_visitorlogin(socket,obj);} );
        socket.on(uk.netevents.STATIONLIST,function(obj){ uk.hall.on_station_quest(socket,obj);} );
        socket.on(uk.netevents.STATIONSEL,function(obj){ uk.hall.on_station_sel(socket,obj);} );
        socket.on(uk.netevents.OUTCARD,function(obj){ uk.hall.on_useroutcard(socket,obj);} );
        socket.on(uk.netevents.FINISHROUND,function(obj){ uk.hall.on_finishround(socket,obj);} );
    },

    on_disconnect:function(socket){
		console.log('a user disconnected:'+socket.name);
        if(socket.user != null){
            this.user_logout(socket.user);
            socket.user = null;
        }
    },

    /** 用户登录 */
    user_login:function(u){
		//将新加入用户的唯一标识当作socket的名称，后面退出的时候会用到
        u.sock.name = u.info.id;
        u.sock.user = u;
		
		//检查在线列表，如果不在里面就加入
		if(!this.users.hasOwnProperty(u.info.id)) {
		    this.users[u.info.id] = u;
			//在线人数+1
			this.usercount++;
		}

        var msg={success:true,info:u.info,visitor:u.visitor};
        if(!u.currole) msg.createrole = true;
		u.sock.emit(uk.netevents.LOGIN,msg);
        if(u.currole){
            var r = u.currole;
		    u.sock.emit(uk.netevents.SWITCHROLE,{success:true,id:r.id,name:r.user.info.name,roleid:r.template.id,props:r.props,equips:r.equips});
        } 
    },

    /** 登出 */
    user_logout:function(user){
        /** 在房间，离开房间 */
        var r = user.currole;
        if(r.room){
            r.room.player_leave(r);
        }

        /** 保存用户数据 */
        this.save_user_data(user);

        /** 移除列表 */
		if(this.users.hasOwnProperty(user.id)) {			
			delete this.users[socket.name];
			this.usercount--;
		}

        user.sock.user = null;
        user.sock = null;
        console.log('user logout:'+user.info.name);
    },

    on_register:function(socket,obj){
		console.log('register msg');
        if(socket.user != null && !socket.user.visitor){
            user_logout(socket.user);
            socket.user = null;
        }
        uk.db.exists(obj.name,function(err,exist){
            if(exist){
			    _this.throwfailed(socket,uk.netevents.REGISTER,'用户名已经被他人使用',obj.name);
                return;
            }
            if(socket.user != null){
                /**马上过期 */
                uk.db.expire(socket.user.info.id,1);
                /**替换登录名 */
                socket.user.info.id = obj.name;
                socket.user.visitor = false;
                /**重新调用一次登录过程 */
                this.user_login(socket.user);
            }
        });
    },

    on_login:function(socket,obj){
        if(socket.user != null){/** 已经登录过了。退出这个 */
            user_logout(socket.user);
            socket.user = null;
        }
		console.log('login msg');
        var _this = this;
        uk.db.get(obj.name,function(err,suser){
            if(err){
			    _this.throwfailed(socket,uk.netevents.LOGIN,'帐号不存在',obj.name);
            }else{
                var user = JSON.parse(suser);
                /** 密码验证 */
                if(!user.visitor && obj.pass != user.info.password){
                    _this.throwfailed(socket,uk.netevents.LOGIN,'密码错误',obj);
                    return;
                }
                /** 绑定用户 */
                socket.user = user;
                user.sock = socket;
                /** 创建角色 */
                var _firstr = null;
                for(var i in user.roles){
                    var rt = user.roles[i];
                    var r = uk.create_role(rt.templateid,true);
                    r.id = rt.id;
                    r.name = rt.name;
                    r.ownedcards = rt.ownedcards;
                    r.equips = rt.equips;
                    r.user = user;
                    r.props = rt.props;
                    if(rt.exprops)
                        r.exprops = rt.exprops;
                    /**关卡 */
                    for(var sk in rt.stations){
                        var s = uk.create_station(sk);
                        s.cards = rt.stations[sk];
                        r.stations[sk] = s;
                    }
                    r.reset(rt.props.lv);
                    user.roles[i] = r;
                    _firstr = _firstr?_firstr:r;
                }
                user.currole = user.currole ? user.roles[user.currole]:_firstr;
                _this.user_login(user);
            }
        });
    },
    on_createrole:function(socket,obj){
		var u = socket.user;
		if(u==null||u.currole){/** 只有没有角色时，才能使用创建功能 */
			this.throwfailed(socket,uk.netevents.CREATEROLE,'非法的网络消息->当前状态不能使用创建角色功能');
			return;
		}
		var r = uk.create_role(obj.id);
		if(r == null){
			this.throwfailed(socket,uk.netevents.CREATEROLE,'非法的网络消息->指定的角色类型不存在:',obj.id);
			return;
		}
		r.id = uk.getnewguid();
		r.user = u;
		u.roles[r.id] = r;
        u.currole = r;
        /**刚创建的角色，加几个关卡进去 */
        var n = 0;
        for(var i in uk.stations){
            var s = uk.stations[i];
            if(s.type == uk.room_types.PLAYER) continue;/**不要加入玩家对战的 */
            r.stations[i] = uk.create_station(i);
            /**给3个选项 */
            if(++n >= 3)
                break;
        }
        console.log('create role:'+r.id);

		socket.emit(uk.netevents.CREATEROLE,{success:true,id:r.id,name:r.user.info.name,roleid:r.template.id,props:r.props,equips:r.equips}); 
    },
    on_station_quest:function(socket,obj){
		var u = socket.user;
		if(u==null||!u.currole){/** 没有找到角色 */
			this.throwfailed(socket,uk.netevents.HINT,'非法的关卡请求消息->角色已经不存在了:',obj.id);
			return;
		}
		var r = u.currole;
        var stations = {};
        for(var k in r.stations){
            var s = r.stations[k];
            stations[k] = {id:s.template.id,name:s.template.name,type:s.template.type};
        }
        u.sock.emit(uk.netevents.STATIONLIST,stations);
    },
    on_station_sel:function(socket,obj){
		var u = socket.user;
		if(u==null||!u.currole){/** 没有找到角色 */
			this.throwfailed(socket,uk.netevents.HINT,'非法的网络消息->角色已经不存在了:',obj.id);
			return;
		}
		var r = u.currole;
        if(r.room != null){
			this.throwfailed(socket,uk.netevents.HINT,'非法的关卡选择消息->玩家正在房间中:',obj.id);
			return;
        }
        /**不属于我的关卡，则不处理 */
        if(!r.stations.hasOwnProperty(obj.id)){
			this.throwfailed(socket,uk.netevents.HINT,'非法的关卡选择消息->关卡不存在:',obj.id);
            return;
        }

        var sta = r.stations[obj.id];
        if(sta.template.type == uk.room_types.MONSTER || sta.template.type == uk.room_types.PLAYER){
            var room = uk.create_room(uk.getnewguidn(),null,sta.template);
            uk.rooms[room.id] = room;

            /** 用户进入 */
            room.player_enter(r,-1);
            /** 进入之后直接开始 */
            if(sta.template.type == uk.room_types.MONSTER)
                room.player_start(r);

        }else{/**直接把关卡信息发过去 */
            socket.emit(uk.netevents.STATIONSEL,{success:true,station:sta});
        }
    },
    on_enterroom:function(socket,obj){
		var u = socket.user;
		if(u==null||!u.currole){/** 没有找到角色 */
			this.throwfailed(socket,uk.netevents.ENTER,'非法的网络消息->角色已经不存在了:',obj.id);
			return;
		}
		var r = u.currole;
        if(r.room!=null){
			socket.emit('enterroom',{success:false,msg:'您还在其他房间未出去，请先离开'});
            return;
        }
        var room = null;
		if(!uk.rooms.hasOwnProperty(obj.roomid)){
			socket.emit('enterroom',{success:false,msg:'房间已经关闭了'});
			return;
		}else{
            room = uk.rooms[obj.roomid];
        }
        console.log('on_enterroom:',r.name);
		
		/** 让房间自己给用户发送进入或者离开的消息 */
		room.player_enter(r,obj.hasOwnProperty('seat')?parseInt(obj.seat):-1);

		/** 没有大厅概念，所以不需要特别处理，如果有大厅，这里需要发送消息给其他玩家，更新状态 */
    },    
    on_leaveroom:function(socket,obj){
		var u = socket.user;
		if(u==null||!u.currole){/** 没有找到角色 */
			this.throwfailed(socket,uk.netevents.LEAVE,'非法的离开房间消息->角色已经不存在了:',obj);
			return;
		}
		var r = u.currole;
		if(r.room){
            var room = r.room;
            r.room.player_leave(r);
            if(room.player_count()==0){/**房间已空，删除房间 */
                console.log('房间已经无人，关闭房间',room.id);
                delete uk.rooms[room.id];
            }
        }
    },
    on_userready:function(socket,obj){
		var u = socket.user;
		if(u == null||!u.currole){/** 没有找到角色 */
			this.throwfailed(socket,uk.netevents.READY,'非法的开始消息->不存在角色试图开始游戏');
			return;
		}

		var r = u.currole;
		if(r.room == null||r.room.status == uk.room_status.INGAME){
			this.throwfailed(socket,uk.netevents.READY,'非法的开始消息->未进入战场',u.info.name);
			return;
		}

        if(r.room.type != uk.room_types.NONE){
			this.throwfailed(socket,uk.netevents.READY,'非法的开始消息->战斗已开始或者已结束'+r.name);
            return;
        }

		/** 用户开始啦 */
		r.room.player_start(r); 
    },

    /** 游客登录 */
    on_visitorlogin:function(socket,obj){
        if(socket.user != null){
			this.throwfailed(socket,uk.netevents.HINT,'非法的网络消息->已登录游戏却试图使用游客进行游戏');
            return;
        }
        var u = this.create_user(socket.name);
        u.sock = socket;
        u.visitor = true;
        u.info.password = '';
        
        this.user_login(u);
    },

    /** 出牌 */
    on_useroutcard:function(socket,obj){
		var u = socket.user;
		if(u == null||!u.currole){/** 没有找到角色 */
			this.throwfailed(socket,uk.netevents.OUTCARD,'非法的出牌消息->不存在角色试图出牌');
			return;
		}

		var r = u.currole;
		if(r.room == null||r.room.status != uk.room_status.INGAME){
			this.throwfailed(socket,uk.netevents.OUTCARD,'非法的出牌消息->未进入战场',u.info.name);
			return;
		}

		/** 出牌 */
		r.room.player_outcard(r,obj.card,obj.target); 
    },

    /** 回合结束 */
    on_finishround:function(socket,obj){
		var u = socket.user;
		if(u == null||!u.currole){/** 没有找到角色 */
			this.throwfailed(socket,uk.netevents.ENDROUND,'非法的网络消息->不存在角色试图回合结束');
			return;
		}

		var r = u.currole;
		if(r.room == null||r.room.status != uk.room_status.INGAME){
			this.throwfailed(socket,uk.netevents.ENDROUND,'非法的回合结束消息->未进入战场',u.info.name);
			return;
		}

        if(r.room.whoturn != r.seat){
			this.throwfailed(socket,uk.netevents.ENDROUND,'非法的回合结束消息->不在角色出牌阶段',r.name);
			return;
        }

		/** 回合结束 */
		r.room.finish_round(); 
    },

    /** 保存用户数据 */
    save_user_data:function(u,callback,thisobj){
        if(u.currole == null)
            return; /**无角色，无需保存 */
        var _this = this;
        var _val = {
            currole:u.currole.id,
            visitor:u.visitor,
            info:u.info
        };
        var _roles = {};
        for(var i in u.roles){
            var r = u.roles[i];
            var rt = {
                id:r.id,
                name:r.name,
                templateid:r.template.id,
                props:r.props,
                exprops:r.exprops,
                ownedcards:r.cards,
                equips:r.equips,
                tasks:r.tasks,
                stations:{}
            }
            /**关卡数据*/
            for(var k in r.stations){
                rt.stations[k] = r.stations[k].cards;
            }
            _roles[i] = rt;
        }
        _val.roles = _roles;
        var args=[];
        for(var i = 2;i<arguments.length;++i)
            args.push(arguments[i]);
        var sval = JSON.stringify(_val);
        this.savequeue ++;
        var _this = this;
        uk.db.set(_val.info.id,sval,function(err,reply){
            if(err){
                console.log('error --> 保存玩家数据失败 >>',_val.info.name);
                return;
            }
            if(callback){
                callback.apply(thisobj,args);
            }
            console.log('success --> 保存玩家数据完成 >>',_val.info.name);
            if(_val.visitor){
                /**访客数据保留72小时 */
                uk.db.expire(_val.info.id,72*3600);
            }
            _this.savequeue --;
            if(_this.savequeue == 0 && _this.savequeue_quest_finish && _this.status == uk.hall_status.CLOSING){
                _this.status = uk.hall_status.END;
                if(_this.shutdown_callback){
                    _this.shutdown_callback();
                }
            }
        });
    },

    /** 提示 */
    throwfailed:function(socket,netevt,msg,tip=null){
        if(tip)
            console.log(msg,' --> ',tip);
        else
            console.log(msg);
        socket.emit(netevt,{success:false,msg:msg});
    }
};